package com.xlh.dokka.svc.service;

import com.xlh.dokka.api.DokkaContainerService;
import com.xlh.dokka.api.DokkaMagicService;
import com.xlh.dokka.api.dto.DokkaClusterJoinDTO;
import com.xlh.dokka.api.exception.DokkaException;
import com.xlh.dokka.svc.core.client.DockerClient;
import com.xlh.dokka.svc.core.model.Container;
import com.xlh.dokka.svc.dao.DokkaContainerMapper;
import com.xlh.util.SshUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @author cheer
 */
@Service
public class DokkaMagicServiceImpl implements DokkaMagicService {

    @Autowired
    private DokkaContainerService dokkaContainerService;

    @Autowired
    private DokkaContainerMapper dokkaContainerMapper;

    @Override
    public List<Long> adjustResolution(List<Long> dokkaIds, Double length, Double width) {
        if (CollectionUtils.isEmpty(dokkaIds)) {
            return new ArrayList<>();
        }

        List<Container> containers = dokkaContainerMapper.listByIds(dokkaIds);
        if (CollectionUtils.isEmpty(containers)) {
            return new ArrayList<>();
        }

        List<Long> successDokkaIds = new ArrayList<>();
        String command = "/usr/lib/clipboard/display.sh " + length + " " + width;
        for (Container container : containers) {
            String execId = DockerClient.createExec(container.getHost(), container.getDockerId(), command);
            if (execId != null && DockerClient.startExec(container.getHost(), execId)) {
                successDokkaIds.add(container.getId());
            }
        }
        return successDokkaIds;
    }

    @Override
    public String getSshExport(Long dokkaId) {
        if (dokkaId == null) {
            return null;
        }

        Container container = dokkaContainerMapper.getById(dokkaId);
        if (container == null) {
            return null;
        }

        Container inspectContainer = DockerClient.inspectContainer(container.getHost(), container.getDockerId());
        if (inspectContainer != null && inspectContainer.getSshExport() != null) {
            return container.getHost() + ":" + inspectContainer.getSshExport();
        }
        return null;
    }

    private static final String[] LINUX_SPECIAL_CHAR = new String[]{"\\", "\"", "`", "$"};

    private static final String[] LINUX_SPECIAL_CHAR_REPLACEMENT = new String[]{"\\\\", "\\\"", "\\`", "\\$"};

    @Override
    public Boolean clipboard(Long dokkaId, String content) {
        if (dokkaId == null) {
            return false;
        }

        String fixedContent = StringUtils.replaceEach(content, LINUX_SPECIAL_CHAR, LINUX_SPECIAL_CHAR_REPLACEMENT);
        String command = "echo -n \"" + fixedContent +
                "\" > /usr/lib/clipboard/text && sh /usr/lib/clipboard/clipboard.sh";
        return dokkaContainerService.execContainer(dokkaId, command);
    }

    @Override
    public void joinCluster(List<DokkaClusterJoinDTO> dokkaClusterJoinDTOS) {
        StringBuilder commandBuilder = new StringBuilder("cat /etc/hosts > /etc/hosts.tmp && ");
        for (DokkaClusterJoinDTO dokkaClusterJoinDTO : dokkaClusterJoinDTOS) {
            commandBuilder.append("sed -i '/").append(dokkaClusterJoinDTO.getHostname())
                    .append("/'d /etc/hosts.tmp && ");
        }
        for (DokkaClusterJoinDTO dokkaClusterJoinDTO : dokkaClusterJoinDTOS) {
            commandBuilder.append("sed -i '$a\\").append(dokkaClusterJoinDTO.getIp()).append("    ")
                    .append(dokkaClusterJoinDTO.getHostname()).append("' /etc/hosts.tmp && ");
        }
        commandBuilder.append("cat /etc/hosts.tmp > /etc/hosts");
        String command = commandBuilder.toString();

        for (DokkaClusterJoinDTO dokkaClusterJoinDTO : dokkaClusterJoinDTOS) {
            dokkaContainerService.execContainer(dokkaClusterJoinDTO.getDokkaId(), command);
        }
    }

    @Override
    public String getExposedPort(Long dokkaId, String exposedPort) {
        if (dokkaId == null) {
            return null;
        }

        Container container = dokkaContainerMapper.getById(dokkaId);
        if (container == null) {
            return null;
        }

        Integer port = DockerClient.inspectContainerExposedPort(container.getHost(), container.getDockerId(), exposedPort);
        if (port != null) {
            return container.getHost() + ":" + port;
        }
        return null;
    }

    @Override
    public String judge(Long dokkaId, String script) {
        if (dokkaId == null) {
            throw new DokkaException("容器不存在");
        }
        Container container = dokkaContainerMapper.getById(dokkaId);
        if (container == null) {
            throw new DokkaException("容器不存在");
        }

        Container inspectContainer = DockerClient.inspectContainer(container.getHost(), container.getDockerId());
        if (inspectContainer == null) {
            throw new DokkaException("容器不存在");
        }
        if (!"running".equals(inspectContainer.getStatus())) {
            throw new DokkaException("容器未运行");
        }
        if (inspectContainer.getSshExport() == null) {
            throw new DokkaException("容器网络异常");
        }

        try (SshUtil sshUtil = SshUtil.newInstance("root", "root",
                container.getHost(), inspectContainer.getSshExport())) {
            String fixedContent = StringUtils.replaceEach(script, LINUX_SPECIAL_CHAR, LINUX_SPECIAL_CHAR_REPLACEMENT);
            return sshUtil.execWithError(fixedContent);
        } catch (Exception e) {
            throw new DokkaException("请求失败，请稍后重试");
        }
    }
}
